package core.proto.rightwindow;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Properties;

import javax.swing.text.Caret;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

import net.htmlparser.jericho.Source;
import net.htmlparser.jericho.TextExtractor;

import org.apache.commons.io.FilenameUtils;

import com.oreilly.servlet.HttpMessage;

import core.proto.AllComponents;
import core.proto.InfoViz;
import core.proto.Util;
import core.proto.annotation.Annotation;
import core.proto.annotation.AnnotationManager;
import core.proto.annotation.AnnotationUI;
import core.proto.annotation.DocAnnotationModel;
import core.proto.annotation.DocAnnotationUI;
import core.proto.annotation.MapAnnotationUI;
import core.proto.annotation.MapAnnotationModel;
import core.proto.annotation.TimelineAnnotationUI;
import core.proto.annotation.TimelineAnnotationModel;
import core.proto.annotation.AnnotationModel.AnnotationLocation;
import core.proto.search.HtmlTextExtractor;

/**
 * Class with methods to communicate updates between annotation and its associate post it. 
 * 
 * Also, takes care of broadcasting PostIt updates to the server.  
 */
public class LeftRightCommunicator {

	private LeftRightCommunicator() {}

	static Hashtable<AnnotationUI, PostIt> anno2Post;
	static Hashtable<PostIt, AnnotationUI> post2Anno;
	
	//FOR STATE SAVING
	public static Hashtable<AnnotationUI, PostIt> prevAnno2Post;
	public static Hashtable<PostIt, AnnotationUI> prevPost2Anno;

	static {
		anno2Post = new Hashtable<AnnotationUI, PostIt>();
		post2Anno = new Hashtable<PostIt, AnnotationUI>();
		
		//FOR STATE SAVING
		prevPost2Anno = new Hashtable<PostIt, AnnotationUI>();
		prevAnno2Post = new Hashtable<AnnotationUI, PostIt>();
	}

	private static void addPostItForAnnotation (AnnotationUI ui) {
			// Create post it
			PostIt postIt;
			
			if(((Object) ui) instanceof MapAnnotationUI){
				postIt = new PostIt(InfoViz.userToken, "Annotation from Map");
				MapAnnotationModel mam = (MapAnnotationModel)ui.getModel();
				postIt.sticky_context = mam.getWaypointIconPos().toString();
			}
			else if(((Object) ui) instanceof DocAnnotationUI){
				
				postIt = new PostIt(InfoViz.userToken, true);
				DocAnnotationModel dam = (DocAnnotationModel)ui.getModel();
				postIt.sticky_context = FilenameUtils.getBaseName(AllComponents.getCurrentPath());
			}
			else if(((Object) ui) instanceof TimelineAnnotationUI){
				postIt = new PostIt(InfoViz.userToken, "Annotation from Timeline");
				TimelineAnnotationModel tam = (TimelineAnnotationModel)ui.getModel();
				postIt.sticky_context = tam.getRowName();
			}
			else{
				postIt = new PostIt(InfoViz.userToken, false);
			}
			
			// Add to board pane
			BoardPane.getInstance().addPostItFromLeftWindow(postIt);
			// Associate the annotation with the post it.
			anno2Post.put(ui, postIt);
			post2Anno.put(postIt, ui);
	}

	/**
	 * Call when annotation is updated. 
	 * Updates existing corresponding post it. 
	 * Pushes the updates up to the server.  
	 * @param ui
	 */
	public static void annotationUpdated (AnnotationUI ui) {
		synchronized(BoardPane.lock){
			PostIt postIt = anno2Post.get(ui);
			// look up post it and update its text
			
			
			if (Annotation.shouldDeleteAnnotationWith(ui.getUserText())){
				// Tell whiteboard to remove it. 
				
				if(postIt != null){
					BoardPane.getInstance().removePostIt(anno2Post.get(ui));
		
					// Update hash tables.
					anno2Post.get(ui).delete();
					pushPostItUpdates2Server (postIt);
				}
				
				
			}else{
				if (! anno2Post.containsKey(ui)) {
					addPostItForAnnotation (ui);
				
				
					anno2Post.get(ui).textUpdate(ui.getUserText());
				}
				else{
					anno2Post.get(ui).textUpdate(ui.getUserText());
				}
				
				pushPostItUpdates2Server (anno2Post.get(ui));
			}
			// regardless of whehter we removed PostIt, we send an update 
			// to the other client, which we assume will update accordingly
			// (it has to because it's running the same codebase as us and we 
			// have coded that in). 
			
		}
	}

	/**
	 * Analogous to the annotation update but pushes updates back to the annotations. 
	 * @param postIt
	 */
	public static void postItUpdated (PostIt postIt) {
		pushPostItUpdates2Server (postIt);
		if (post2Anno.containsKey(postIt)){
			// Update associated annotation.  
			
			String textOut = postIt.getText().substring(postIt.textBeginPosition(
					postIt.titleEndPosition()));
			
			
			boolean deleted = post2Anno.get(postIt).externalSetText (textOut);
			// update hash table from deletions. 
			if (deleted) {
				anno2Post.remove(post2Anno.get(postIt));
				post2Anno.remove(postIt);
				BoardPane.getInstance().removePostIt(postIt);
			}
		} else {
			// Check if we should delete the post it anyhow. 
			/*if (Annotation.shouldDeleteAnnotationWith(postIt.getText())){netscape
				BoardPane.getInstance().removePostIt(postIt);
			}*/
		}
	}

	private static void pushPostItUpdates2Server (final PostIt postIt) {
		final String networkString;
		try {
			networkString = postIt.piNetworker.toNetworkString();
		} catch (IOException e1) {
			return;
		}
		new Thread(){
			public void run() {
				try {
					WebUtil.sendPostIt(networkString);
				} catch (IOException e) {
					System.err.println("Error sending out postIt update.");
				}catch(IllegalArgumentException e){
					//ERIC COMMENTED OUT FOR DEBUGGING
				}
			}
		}.start();
	}
}
